package com.chensi.admin.web.oauth2;

import com.chensi.admin.web.common.Constants;
import com.chensi.admin.web.domain.SysUserToken;
import com.chensi.admin.web.domain.WebUser;
import com.chensi.admin.web.exception.BaseException;
import com.chensi.admin.web.service.SysLoginService;
import com.chensi.admin.web.service.WebUserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Set;

import static com.chensi.admin.web.common.BaseErrorCode.TOKEN_ERROR;

/**
 * @Author: si.chen
 * @Date: 2019/6/19 14:00
 */
@Component
public class OAuth2Realm extends AuthorizingRealm {

    private final WebUserService webUserService;

    private final SysLoginService sysLoginService;

    @Autowired
    public OAuth2Realm(WebUserService webUserService, SysLoginService sysLoginService) {
        this.webUserService = webUserService;
        this.sysLoginService = sysLoginService;
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof OAuth2Token;
    }

    /**
     * 授权
     * 触发点：hasPermission时
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        WebUser user = (WebUser) principals.getPrimaryPrincipal();
        String userId = user.getId();
        Set<String> permsSet;
        try {
            permsSet = sysLoginService.getUserPermissions(userId);
        } catch (BaseException e) {
            e.printStackTrace();
            throw new UnknownAccountException("不存在的用户");
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(permsSet);
        return info;
    }

    /**
     * 认证(登录时调用)
     * 触发点：subject.login
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String accessToken = (String) authenticationToken.getPrincipal();
        //根据accessToken，查询用户信息（1.redis 2.数据库）
        SysUserToken param = new SysUserToken();
        param.setToken(accessToken);
        SysUserToken sysUserToken = sysLoginService.find(param);
        //token失效
        if (sysUserToken == null || sysUserToken.getExpireTime().getTime() < System.currentTimeMillis()) {
            throw new IncorrectCredentialsException(TOKEN_ERROR.getMessage());
        }
        //查询用户信息
        WebUser user;
        try {
            user = webUserService.get(sysUserToken.getUserId());
        } catch (BaseException e) {
            throw new UnknownAccountException("不存在的用户");
        }
        //账号锁定
        if (Constants.USER_STATE_LOCKED.equals(user.getState())) {
            throw new LockedAccountException("账号已被锁定,请联系管理员");
        }
        return new SimpleAuthenticationInfo(user, accessToken, getName());
    }
}
